/*
pcase.cpp : Defines the entry point for the application.
*/

#include <system.h>
#include <about.h>
#include <commctrl.h>
#include <dbt.h>
#include <kpad.h>
#include <usbdev.h>
#include <wave.h>

#define MAX_LOADSTRING	100
#define	WND_STATUS	1
#define	WND_KPAD	2
#define	WND_WAVE	3

HCURSOR		defcursor;
HINSTANCE	instance;		//current instance
HPEN		grypen,redpen;
RINFO		rinfo;
TCHAR		csfram[]="FRAM";
TCHAR		cserch[]="SRCH";
BEAM		form={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,{
    1438650723,2244,83886354,281,83886354,281,83886354,282,83886353,845,
    83886354,845,83886354,844,83886354,845,83886354,281,83886354,845,
    83886353,845,83886354,845,83886353,282,83886354,281,83886354,282,
    83886353,282,83886354,844,83886354,282,83886353,845,83886354,845,
    83886353,845,83886354,845,83886354,281,83886354,281,83886354,282,
    83886353,845,83886354,281,83886354,282,83886354,282,83886354,281,
    83886354,845,83886354,844,83886354,845,83886354,19797,1430262115,
    1126,83886353,47700,0,0,0}
};

static HANDLE		device;
static HANDLE		thread;
static HWND		hfram;
static HWND		hkid;
static HWND		hkpad;
static HWND		hsrch;
static HWND		hstat;
static HWND		htool;
static HWND		hwave;
static int		parts[]={80,160,240,320,400,-1};
static TCHAR		title[MAX_LOADSTRING];	//The title bar text

static DWORD	WINAPI		DevProc	(LPVOID);
static LRESULT	CALLBACK	WndProc	(HWND,UINT,WPARAM,LPARAM);
static LRESULT	Resize		(HWND,HWND);
static LRESULT	WmCommand	(HWND,WPARAM,LPARAM);
static LRESULT	WmCreate	(HWND,WPARAM,LPARAM);
static LRESULT	WmDestroy	(void);
static LRESULT	WmDeviceChange	(HWND,WPARAM);
static LRESULT	WmPaint		(HWND,WPARAM,LPARAM);
static LRESULT	WmUser		(HWND,WPARAM,LPARAM);

static ATOM InitFram(HINSTANCE hInstance){
    WNDCLASSEX x;

    x.cbSize		=sizeof(WNDCLASSEX); 
    x.style		=CS_HREDRAW|CS_VREDRAW;
    x.lpfnWndProc	=(WNDPROC)WndProc;
    x.cbClsExtra	=0;
    x.cbWndExtra	=0;
    x.hInstance		=hInstance;
    x.hIcon		=LoadIcon(hInstance,(LPCTSTR)IDI_PCASE);
    x.hCursor		=defcursor;
    x.hbrBackground	=(HBRUSH)(COLOR_MENU+1);
    x.lpszMenuName	=(LPCTSTR)IDC_PCASE;
    x.lpszClassName	=csfram;
    x.hIconSm		=LoadIcon(x.hInstance,(LPCTSTR)IDI_SMALL);
    return RegisterClassEx(&x);
}

static void Remode(BOOL show){
    HWND	hwnd;

    switch(rinfo.mode){
    case MOD_LEARNING:
    case MOD_PRESET:
	hwnd=hwave;
	break;
    default:
	hwnd=hkpad;
    }
    if(hkid!=hwnd){
	if(show){
	    ShowWindow(hwnd,SW_SHOW);
	    Resize(hfram,hwnd);
	}
	if(hkid)
	    ShowWindow(hkid,SW_HIDE);
	hkid=hwnd;
    }
}

static LRESULT Resize(HWND hwnd,HWND hkid){
    RECT    rf,rs;

    MoveWindow(hstat,0,0,0,0,TRUE);
    GetClientRect(hwnd,&rf);
    GetClientRect(hstat,&rs);
    if(hkid)
	MoveWindow(hkid,0,0,rf.right,rf.bottom+rs.top-rs.bottom,TRUE);
    return 0;
}

static void RInfo(RINFO *inf){
    CHAR    s[255];

    rinfo=*inf;
    wsprintf(s,"%d",inf->key);
    SendMessage(hstat,SB_SETTEXT,1,(LPARAM)(inf->key?s:""));
    wsprintf(s,"%d",inf->acc[0]);
    SendMessage(hstat,SB_SETTEXT,2,(LPARAM)s);
    wsprintf(s,"%d",inf->acc[1]);
    SendMessage(hstat,SB_SETTEXT,3,(LPARAM)s);
    wsprintf(s,"%d",inf->acc[2]);
    SendMessage(hstat,SB_SETTEXT,4,(LPARAM)s);
    wsprintf(s,"%d",inf->mode);
    SendMessage(hstat,SB_SETTEXT,5,(LPARAM)s);
    PostMessage(hfram,WM_USER,RPT_INFO,inf->key);
}

static void RptWave(RPTWAVE *wav){
    U32	i;

    i=wav->seq;
    if(i<countof(form.thunk)){
	form.thunk[i]=wav->thunk;
	if(wav->last){
	    SendMessage(hstat,SB_SETTEXT,0,(LPARAM)"Wave");
	    PostMessage(hfram,WM_USER,RPT_WAVE,wav->seq);
	}
    }
}

DWORD WINAPI DevProc(LPVOID param){
    DWORD	len;
    OVERLAPPED	ola;
    RPTBUFFER	buf;
    RPTDATA	*dat;

    while(1){
	ola.hEvent=NULL;
	ola.Offset=0;
	ola.OffsetHigh=0;
	ReadFile(param,&buf,sizeof(buf),&len,&ola);
	if(GetOverlappedResult(param,&ola,&len,TRUE)&&len){
	    dat=(RPTDATA*)&buf.type;
	    switch(buf.type){
	    case RPT_INFO:
		RInfo((RINFO*)dat);
		break;
	    case RPT_WAVE:
		RptWave((RPTWAVE*)dat);
		break;
	    }
	}
	else break;
    }
    return 0;
}

static LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam){
    switch(message){
    case WM_COMMAND:
	return WmCommand(hwnd,wparam,lparam);
    case WM_CREATE:
	return WmCreate(hwnd,wparam,lparam);
    case WM_DESTROY:
	return WmDestroy();
    case WM_DEVICECHANGE:
	return WmDeviceChange(hwnd,wparam);
    case WM_SIZE:
	return Resize(hwnd,hkid);
    case WM_USER:
	return WmUser(hwnd,wparam,lparam);
    default:
	return DefWindowProc(hwnd,message,wparam,lparam);
    }
    return 0;
}

static LRESULT WmCommand(HWND hwnd,WPARAM wparam,LPARAM lparam){
    DWORD	len;
    OVERLAPPED	ola;
    RPTBUFFER	buf;

    //wmEvent	=HIWORD(wparam);
    switch(LOWORD(wparam)){
    case HELP_ABOUT:
	DialogBox(instance,(LPCTSTR)IDD_ABOUTBOX,hwnd,(DLGPROC)About);
	break;
    case FILE_EXIT:
	DestroyWindow(hwnd);
	break;
    case TOOLS_WRITE:
	FillMemory(&buf,sizeof(buf),0);
	ola.hEvent=NULL;
	ola.Offset=0;
	ola.OffsetHigh=0;
	WriteFile(device,&buf,sizeof(buf),&len,&ola);
	GetOverlappedResult(device,&ola,&len,TRUE);
	break;
    default:
	return DefWindowProc(hwnd,WM_COMMAND,wparam,lparam);
    }
    return 0;
}

static LRESULT WmCreate(HWND hwnd,WPARAM wparam,LPARAM lparam){
    hstat=CreateStatusWindow(WS_CHILD|WS_VISIBLE,NULL,hwnd,WND_STATUS);
    SendMessage(hstat,SB_SETPARTS,countof(parts),(LPARAM)parts);
    hfram=hwnd;
    device=OpenHid(DevProc);
    return DefWindowProc(hwnd,WM_CREATE,wparam,lparam);
}

static LRESULT WmDestroy(void){
    CloseHid(device);
    PostQuitMessage(0);
    return 0;
}

static LRESULT WmDeviceChange(HWND hwnd,WPARAM wparam){
    switch(wparam){
    case DBT_DEVICEREMOVECOMPLETE:
	CloseHid(device);
	device=INVALID_HANDLE_VALUE;
	break;
    case DBT_DEVNODES_CHANGED:
	CloseHid(device);
    case DBT_DEVICEARRIVAL:
	device=OpenHid(DevProc);
	break;
    default:
	return 1;
    }
    ShowWindow(hkid,device==INVALID_HANDLE_VALUE?SW_HIDE:SW_SHOW);
    return 0;
}

LRESULT WmPaint(HWND hwnd,WPARAM wparam,LPARAM lparam){
    HDC		hdc;
    PAINTSTRUCT ps;

    hdc=BeginPaint(hwnd,&ps);
    if(device==INVALID_HANDLE_VALUE){
	SelectObject(hdc,GetSysColorBrush(COLOR_MENU));
	SelectObject(hdc,GetStockObject(NULL_PEN));
	Rectangle(hdc,ps.rcPaint.left,ps.rcPaint.top,ps.rcPaint.right+1,ps.rcPaint.bottom-20);
    }
    else{
	SelectObject(hdc,GetStockObject(WHITE_BRUSH));
	SelectObject(hdc,GetStockObject(NULL_PEN));
	Rectangle(hdc,ps.rcPaint.left,ps.rcPaint.top,ps.rcPaint.right+1,ps.rcPaint.bottom-20);
    }
    EndPaint(hwnd,&ps);
    return 0;
}

static LRESULT WmUser(HWND hwnd,WPARAM wparam,LPARAM lparam){
    Remode(TRUE);
    if(hkid)
	SendMessage(hkid,WM_USER,wparam,lparam);
    return 0;
}

//-----------------------------------------------------------------------------

int APIENTRY WinMain(HINSTANCE hinst,HINSTANCE prev,LPTSTR cmd,int show){
    MSG	    msg;
    HACCEL  acc;

    defcursor=LoadCursor(NULL,IDC_ARROW);
    instance=hinst;
    InitCommonControls();
    InitFram(hinst);
    InitKPad(hinst);
    InitWave(hinst);
    LoadString(hinst,IDS_APP_TITLE,title,MAX_LOADSTRING);
    if(!(hfram=CreateWindow(csfram,title,WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,
	CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,
	hinst,NULL)))
	return 0;
    if(!(hkpad=CreateKPad(hinst,hfram,WND_KPAD)))
	return 0;
    if(!(hwave=CreateWave(hinst,hfram,WND_WAVE)))
	return 0;
    redpen=CreatePen(PS_SOLID,0,RGB(255,0,0));
    Remode(device!=INVALID_HANDLE_VALUE);
    ShowWindow(hfram,show);
    UpdateWindow(hfram);
    acc=LoadAccelerators(hinst,(LPCTSTR)IDC_PCASE);
    while(GetMessage(&msg,NULL,0,0)){
	if(!TranslateAccelerator(msg.hwnd,acc,&msg)){
	    TranslateMessage(&msg);
	    DispatchMessage(&msg);
	}
    }
    DeleteObject(redpen);
    return (int)msg.wParam;
}
